#include "lcd_mmap.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include "font.h"
#include "lcd.h"
// LCD屏幕文件内存映射

unsigned int *lcdmmap(int *fd)
{
	*fd = open("/dev/fb0", O_RDWR); // 打开屏幕文件
	if (*fd < 0)
	{
		perror("open fail");
		return NULL;
	}
	unsigned int *p = mmap(NULL,				   // 系统自动寻找合适的内存映射后的起始地址
						   800 * 480 * 4,		   // 映射的内存字节大小
						   PROT_READ | PROT_WRITE, // 映射内存的权限可读可写
						   MAP_SHARED,			   // 映射的内存进程共享
						   *fd,					   // 要映射的文件描述符
						   0);					   // 映射后文件偏移量
	if (p == (void *)-1)
	{
		perror("mmap fail");
		close(*fd);
		return NULL;
	}
	return p;
}

char color_buf[800 * 480 * 4] = {0};

unsigned int *g_fb = NULL;

int g_fd_lcd;

font *g_font=NULL;;

// 描点操作
void lcd_draw_point(int x, int y, unsigned int color)
{
    *(g_fb + y * 800 + x) = color;
}

// 获点操作
unsigned int lcd_read_point(int x, int y)
{
    return *(g_fb + y * 800 + x);
}

// 清屏操作
void lcd_clear(unsigned int color)
{
    int x, y;

    for (y = 479; y >= 0; y--)
    {
        for (x = 0; x < 800; x++)
        {
            // 对每个像素点进行赋值
            lcd_draw_point(x, y, color);
        }
    }
}

// 填充函数
void lcd_fill(int x, int y, int width, int height, unsigned int color)
{
    int x_s = x;
    int y_s = y;
    int x_e = x + width;
    int y_e = y + height;

    if (x_e > LCD_WIDTH)
        x_e = LCD_WIDTH;

    if (y_e > LCD_HEIGHT)
        y_e = LCD_HEIGHT;

    for (y = y_s; y < y_e; y++)
    {
        for (x = x_s; x < x_e; x++)
        {
            // 对每个像素点进行赋值
            lcd_draw_point(x, y, color);
        }
    }
}

// 位图显示
int lcd_draw_bmp( char *pathname, int x, int y)
{

    // 打开4.bmp
    int fd_bmp = open(pathname, O_RDONLY);

    if (fd_bmp < 0)
    {
        printf("open %s fail\n", pathname);
        return -1;
    }

    // 位图文件头
    BITMAPFILEHEADER file_head;
    read(fd_bmp, &file_head, sizeof(file_head));
    // printf("%s图片大小:%d bytes\n", pathname, file_head.bfSize);

    // 位图信息段，获取位图的高度、宽度、颜色深度
    BITMAPINFOHEADER info_head;
    read(fd_bmp, &info_head, sizeof(info_head));
    // printf("%s图片尺寸:宽%ld 高%ld\n", pathname, info_head.biWidth, info_head.biHeight);
    // printf("%s图片颜色深度:%d\n", pathname, info_head.biBitCount);

    int bmp_rgb_size = info_head.biWidth * info_head.biHeight * info_head.biBitCount / 8;

    // 定义一个变长数组
    char bmp_buf[bmp_rgb_size];

    // 读取该bmp的所有RGB的数据
    read(fd_bmp, bmp_buf, bmp_rgb_size);

    // 关闭bmp文件
    close(fd_bmp);

    // 开始显示图片
    int x_s = x;
    int y_s = y;
    int x_e = x_s + info_head.biWidth;
    int y_e = y_s + info_head.biHeight;

    int x_pos, y_pos;

    unsigned int color;
    int i = 0;

    for (y_pos = y_e - 1; y_pos >= y_s; y_pos--)
    {
        for (x_pos = x_s; x_pos < x_e; x_pos++, i += 3)
        {

            color = (bmp_buf[i + 2] << 16) | (bmp_buf[i + 1] << 8) | bmp_buf[i];
            lcd_draw_point(x_pos, y_pos, color);
        }
    }

    return 0;
}

int lcd_draw_pokemon( char *pathname, int x, int y)
{

    int fd_bmp = open(pathname, O_RDONLY);

    if (fd_bmp < 0)
    {
        printf("open %s fail\n", pathname);
        return -1;
    }

    // 位图文件头
    BITMAPFILEHEADER file_head;
    read(fd_bmp, &file_head, sizeof(file_head));
    // printf("%s图片大小:%d bytes\n", pathname, file_head.bfSize);

    // 位图信息段，获取位图的高度、宽度、颜色深度
    BITMAPINFOHEADER info_head;
    read(fd_bmp, &info_head, sizeof(info_head));
    // printf("%s图片尺寸:宽%ld 高%ld\n", pathname, info_head.biWidth, info_head.biHeight);
    // printf("%s图片颜色深度:%d\n", pathname, info_head.biBitCount);

    int bmp_rgb_size = info_head.biWidth * info_head.biHeight * info_head.biBitCount / 8;

    // 定义一个变长数组
    char bmp_buf[bmp_rgb_size];

    // 读取该bmp的所有RGB的数据
    read(fd_bmp, bmp_buf, bmp_rgb_size);

    // 关闭bmp文件
    close(fd_bmp);

    // 开始显示图片
    int x_s = x;
    int y_s = y;
    int x_e = x_s + info_head.biWidth;
    int y_e = y_s + info_head.biHeight;

    int x_pos, y_pos;

    unsigned int color;
    int i = 0;

    for (y_pos = y_e - 1; y_pos >= y_s; y_pos--)
    {
        for (x_pos = x_s; x_pos < x_e; x_pos++, i += 3)
        {

            color = (bmp_buf[i + 2] << 16) | (bmp_buf[i + 1] << 8) | bmp_buf[i];

            if(color >= 0xF10000)
                continue;

            lcd_draw_point(x_pos, y_pos, color);
        }
    }

    return 0;
}




int lcd_open( char *pathname)
{
    // 打开/dev/fb0
    int g_fd_lcd = open(pathname, O_RDWR);

    if (g_fd_lcd < 0)
    {
        printf("open %s fail\n", pathname);
        return -1;
    }

    // 将设备文件/dev/fb0映射到内存
    g_fb = mmap(NULL,                   // 映射区的起始地址由系统自动分配
                800 * 480 * 4,          // 映射内存的大小，往往填写文件的大小
                PROT_READ | PROT_WRITE, // 映射区的保护形式，当前是可读可写
                MAP_SHARED,             // 共享，把映射内存的数据同步到文件
                g_fd_lcd,               // 映射的文件描述符
                0);                     // 文件的偏移量，0就不需要进行的偏移

    if (g_fb == MAP_FAILED)
    {
        printf("mmap fail\n");
        return -1;
    }

    return 0;
}

int lcd_close(void)
{
    if (g_fd_lcd > 0)
        close(g_fd_lcd);

    // 解除内存映射
    if (g_fb)
	{
		munmap(g_fb, 800 * 480 * 4);
		g_fb=NULL;
	}
        
	

    return 0;
}


void unlcd_mmap(int fd, unsigned int *lcdp)
{
	// 资源回收
	munmap(lcdp, 800 * 480 * 4); // 取消映射
	close(fd);					 // 关闭文件
}
